home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / usr / share / pygtk / 2.0 / codegen / reversewrapper.py < prev    next >
Text File  |  2006-01-20  |  26KB  |  668 lines

  1. ### -*- python -*-
  2. ### Code to generate "Reverse Wrappers", i.e. C->Python wrappers
  3. ### (C) 2004 Gustavo Carneiro <gjc@gnome.org>
  4. import argtypes
  5.  
  6. def join_ctype_name(ctype, name):
  7.     '''Joins a C type and a variable name into a single string'''
  8.     if ctype[-1] != '*':
  9.         return " ".join((ctype, name))
  10.     else:
  11.         return "".join((ctype, name))
  12.  
  13.  
  14. class CodeSink(object):
  15.     def __init__(self):
  16.         self.indent_level = 0 # current indent level
  17.         self.indent_stack = [] # previous indent levels
  18.  
  19.     def _format_code(self, code):
  20.         assert isinstance(code, str)
  21.         l = []
  22.         for line in code.split('\n'):
  23.             l.append(' '*self.indent_level + line)
  24.         if l[-1]:
  25.             l.append('')
  26.         return '\n'.join(l)
  27.     
  28.     def writeln(self, line=''):
  29.         raise NotImplementedError
  30.     
  31.     def indent(self, level=4):
  32.         '''Add a certain ammount of indentation to all lines written
  33.         from now on and until unindent() is called'''
  34.         self.indent_stack.append(self.indent_level)
  35.         self.indent_level += level
  36.  
  37.     def unindent(self):
  38.         '''Revert indentation level to the value before last indent() call'''
  39.         self.indent_level = self.indent_stack.pop()
  40.  
  41.  
  42. class FileCodeSink(CodeSink):
  43.     def __init__(self, fp):
  44.         CodeSink.__init__(self)
  45.         assert isinstance(fp, file)
  46.         self.fp = fp
  47.  
  48.     def writeln(self, line=''):
  49.         self.fp.write(self._format_code(line))
  50.  
  51. class MemoryCodeSink(CodeSink):
  52.     def __init__(self):
  53.         CodeSink.__init__(self)
  54.         self.lines = []
  55.  
  56.     def writeln(self, line=''):
  57.         self.lines.append(self._format_code(line))
  58.  
  59.     def flush_to(self, sink):
  60.         assert isinstance(sink, CodeSink)
  61.         for line in self.lines:
  62.             sink.writeln(line.rstrip())
  63.         self.lines = []
  64.  
  65.     def flush(self):
  66.         l = []
  67.         for line in self.lines:
  68.             l.append(self._format_code(line))
  69.         self.lines = []
  70.         return "".join(l)
  71.  
  72. class ReverseWrapper(object):
  73.     '''Object that generates a C->Python wrapper'''
  74.     def __init__(self, cname, is_static=True):
  75.         assert isinstance(cname, str)
  76.  
  77.         self.cname = cname
  78.         ## function object we will call, or object whose method we will call 
  79.         self.called_pyobj = None
  80.         ## name of method of self.called_pyobj we will call
  81.         self.method_name = None 
  82.         self.is_static = is_static
  83.  
  84.         self.parameters = []
  85.         self.declarations = MemoryCodeSink()
  86.         self.body = MemoryCodeSink()
  87.         self.cleanup_actions = []
  88.         self.pyargv_items = []
  89.         self.pyargv_optional_items = []
  90.  
  91.     def set_call_target(self, called_pyobj, method_name=None):
  92.         assert called_pyobj is not None
  93.         assert self.called_pyobj is None
  94.         self.called_pyobj = called_pyobj
  95.         self.method_name = method_name
  96.  
  97.     def set_return_type(self, return_type):
  98.         assert isinstance(return_type, ReturnType)
  99.         self.return_type = return_type
  100.  
  101.     def add_parameter(self, param):
  102.         assert isinstance(param, Parameter)
  103.         self.parameters.append(param)
  104.  
  105.     def add_declaration(self, decl_code):
  106.         self.declarations.writeln(decl_code)
  107.  
  108.     def add_pyargv_item(self, variable, optional=False):
  109.         if optional:
  110.             self.pyargv_optional_items.append(variable)
  111.         else:
  112.             self.pyargv_items.append(variable)
  113.  
  114.     def write_code(self, code,
  115.                  cleanup=None,
  116.                  failure_expression=None,
  117.                  failure_cleanup=None):
  118.         '''Add a chunk of code with cleanup and error handling
  119.  
  120.         This method is to be used by TypeHandlers when generating code
  121.  
  122.         Keywork arguments:
  123.         code -- code to add
  124.         cleanup -- code to cleanup any dynamic resources created by @code
  125.                    (except in case of failure) (default None)
  126.         failure_expression -- C boolean expression to indicate
  127.                               if anything failed (default None)
  128.         failure_cleanup -- code to cleanup any dynamic resources
  129.                            created by @code in case of failure (default None)
  130.         '''
  131.         if code is not None:
  132.             self.body.writeln(code)
  133.         if failure_expression is not None:
  134.             self.body.writeln("if (%s) {" % failure_expression)
  135.             self.body.indent()
  136.             self.body.writeln("if (PyErr_Occurred())")
  137.             self.body.indent()
  138.             self.body.writeln("PyErr_Print();")
  139.             self.body.unindent()
  140.             if failure_cleanup is not None:
  141.                 self.body.writeln(failure_cleanup)
  142.             for cleanup_action in self.cleanup_actions:
  143.                 self.body.writeln(cleanup_action)
  144.             self.return_type.write_error_return()
  145.             self.body.unindent()
  146.             self.body.writeln("}")
  147.         if cleanup is not None:
  148.             self.cleanup_actions.insert(0, cleanup)
  149.  
  150.     def generate(self, sink):
  151.         '''Generate the code into a CodeSink object'''
  152.         assert isinstance(sink, CodeSink)
  153.  
  154.         self.add_declaration("PyGILState_STATE __py_state;")
  155.         self.write_code(code="__py_state = pyg_gil_state_ensure();",
  156.                         cleanup="pyg_gil_state_release(__py_state);")
  157.  
  158.         for param in self.parameters:
  159.             param.convert_c2py()
  160.  
  161.         assert self.called_pyobj is not None,\
  162.                "Parameters failed to provide a target function or method."
  163.  
  164.         if self.is_static:
  165.             sink.writeln('static %s' % self.return_type.get_c_type())
  166.         else:
  167.             sink.writeln(self.return_type.get_c_type())
  168.         c_proto_params = map(Parameter.format_for_c_proto, self.parameters)
  169.         sink.writeln("%s(%s)\n{" % (self.cname, ", ".join(c_proto_params)))
  170.  
  171.         self.return_type.write_decl()
  172.         self.add_declaration("PyObject *py_retval;")
  173.  
  174.         ## Handle number of arguments
  175.         if self.pyargv_items:
  176.             self.add_declaration("PyObject *py_args;")
  177.             py_args = "py_args"
  178.             if self.pyargv_optional_items:
  179.                 self.add_declaration("int argc = %i;" % len(self.pyargv_items))
  180.                 argc = "argc"
  181.                 for arg in self.pyargv_optional_items:
  182.                     self.body.writeln("if (%s)" % arg)
  183.                     self.body.indent()
  184.                     self.body.writeln("++argc;")
  185.                     self.body.unindent()
  186.             else:
  187.                 argc = str(len(self.pyargv_items))
  188.         else:
  189.             if self.pyargv_optional_items:
  190.                 self.add_declaration("PyObject *py_args;")
  191.                 py_args = "py_args"
  192.                 self.add_declaration("int argc = 0;")
  193.                 argc = "argc"
  194.                 for arg in self.pyargv_optional_items:
  195.                     self.body.writeln("if (%s)" % arg)
  196.                     self.body.indent()
  197.                     self.body.writeln("++argc;")
  198.                     self.body.unindent()
  199.             else:
  200.                 py_args = "NULL"
  201.                 argc = None
  202.  
  203.         self.body.writeln()
  204.         
  205.         if py_args != "NULL":
  206.             self.write_code("py_args = PyTuple_New(%s);" % argc,
  207.                             cleanup="Py_DECREF(py_args);")
  208.             pos = 0
  209.             for arg in self.pyargv_items:
  210.                 try: # try to remove the Py_DECREF cleanup action, if we can
  211.                     self.cleanup_actions.remove("Py_DECREF(%s);" % arg)
  212.                 except ValueError: # otherwise we have to Py_INCREF..
  213.                     self.body.writeln("Py_INCREF(%s);" % arg)
  214.                 self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
  215.                 pos += 1
  216.             for arg in self.pyargv_optional_items:
  217.                 self.body.writeln("if (%s) {" % arg)
  218.                 self.body.indent()
  219.                 try: # try to remove the Py_DECREF cleanup action, if we can
  220.                     self.cleanup_actions.remove("Py_XDECREF(%s);" % arg)
  221.                 except ValueError: # otherwise we have to Py_INCREF..
  222.                     self.body.writeln("Py_INCREF(%s);" % arg)
  223.                 self.body.writeln("PyTuple_SET_ITEM(%s, %i, %s);" % (py_args, pos, arg))
  224.                 self.body.unindent()
  225.                 self.body.writeln("}")
  226.                 pos += 1
  227.  
  228.         self.body.writeln()
  229.  
  230.         # call it
  231.         if self.method_name is None:
  232.             self.write_code("py_retval = PyObject_Call(%s, %s);"
  233.                             % (self.called_pyobj, py_args),
  234.                             cleanup="Py_DECREF(py_retval);",
  235.                             failure_expression="!py_retval")
  236.         else:
  237.             self.add_declaration("PyObject *py_method;")
  238.             self.write_code("py_method = PyObject_GetAttrString(%s, \"%s\");"
  239.                             % (self.called_pyobj, self.method_name),
  240.                             cleanup="Py_DECREF(py_method);",
  241.                             failure_expression="!py_method")
  242.             self.write_code("py_retval = PyObject_CallObject(py_method, %s);"
  243.                             % (py_args,),
  244.                             cleanup="Py_DECREF(py_retval);",
  245.                             failure_expression="!py_retval")
  246.         
  247.         self.return_type.write_conversion()
  248.  
  249.         sink.indent()
  250.         self.declarations.flush_to(sink)
  251.         sink.writeln()
  252.         self.body.flush_to(sink)
  253.         sink.writeln()
  254.         for cleanup_action in self.cleanup_actions:
  255.             sink.writeln(cleanup_action)
  256.         if self.return_type.get_c_type() != 'void':
  257.             sink.writeln()
  258.             sink.writeln("return retval;")
  259.         sink.unindent()
  260.         sink.writeln("}")
  261.  
  262. class TypeHandler(object):
  263.     def __init__(self, wrapper, **props):
  264.         assert isinstance(wrapper, ReverseWrapper)
  265.         self.wrapper = wrapper
  266.         self.props = props
  267.  
  268. class ReturnType(TypeHandler):
  269.  
  270.     def get_c_type(self):
  271.         raise NotImplementedError
  272.  
  273.     def write_decl(self):
  274.         raise NotImplementedError
  275.  
  276.     def write_error_return(self):
  277.         '''Write "return <value>" code in case of error'''
  278.         raise NotImplementedError
  279.  
  280.     def write_conversion(self):
  281.         '''Writes code to convert Python return value in 'py_retval'
  282.         into C 'retval'.  Returns a string with C boolean expression
  283.         that determines if anything went wrong. '''
  284.         raise NotImplementedError
  285.  
  286. class Parameter(TypeHandler):
  287.  
  288.     def __init__(self, wrapper, name, **props):
  289.         TypeHandler.__init__(self, wrapper, **props)
  290.         self.name = name
  291.  
  292.     def get_c_type(self):
  293.         raise NotImplementedError
  294.  
  295.     def convert_c2py(self):
  296.         '''Write some code before calling the Python method.'''
  297.         pass
  298.  
  299.     def format_for_c_proto(self):
  300.         return join_ctype_name(self.get_c_type(), self.name)
  301.  
  302.  
  303. ###---
  304. class StringParam(Parameter):
  305.  
  306.     def get_c_type(self):
  307.         return self.props.get('c_type', 'char *').replace('const-', 'const ')
  308.  
  309.     def convert_c2py(self):
  310.         if self.props.get('optional', False):
  311.             self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
  312.             self.wrapper.write_code(code=("if (%s)\n"
  313.                                           "    py_%s = PyString_FromString(%s);\n"
  314.                                           % (self.name, self.name, self.name)),
  315.                                     cleanup=("Py_XDECREF(py_%s);" % self.name))
  316.             self.wrapper.add_pyargv_item("py_%s" % self.name, optional=True)
  317.         else:
  318.             self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  319.             self.wrapper.write_code(code=("py_%s = PyString_FromString(%s);" %
  320.                                           (self.name, self.name)),
  321.                                     cleanup=("Py_DECREF(py_%s);" % self.name),
  322.                                     failure_expression=("!py_%s" % self.name))
  323.             self.wrapper.add_pyargv_item("py_%s" % self.name)
  324.  
  325. for ctype in ('char*', 'gchar*', 'const-char*', 'char-const*', 'const-gchar*',
  326.               'gchar-const*', 'string', 'static_string'):
  327.     argtypes.matcher.register_reverse(ctype, StringParam)
  328.  
  329.  
  330. class StringReturn(ReturnType):
  331.  
  332.     def get_c_type(self):
  333.         return "char *"
  334.  
  335.     def write_decl(self):
  336.         self.wrapper.add_declaration("char *retval;")
  337.  
  338.     def write_error_return(self):
  339.         self.wrapper.write_code("return NULL;")
  340.  
  341.     def write_conversion(self):
  342.         self.wrapper.write_code(
  343.             code=None,
  344.             failure_expression="!PyString_Check(py_retval)",
  345.             failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a string");')
  346.         self.wrapper.write_code("retval = g_strdup(PyString_AsString(py_retval));")
  347.  
  348. for ctype in ('char*', 'gchar*'):
  349.     argtypes.matcher.register_reverse(ctype, StringReturn)
  350.  
  351.  
  352.  
  353. class VoidReturn(ReturnType):
  354.  
  355.     def get_c_type(self):
  356.         return "void"
  357.  
  358.     def write_decl(self):
  359.         pass
  360.  
  361.     def write_error_return(self):
  362.         self.wrapper.write_code("return;")
  363.  
  364.     def write_conversion(self):
  365.         self.wrapper.write_code(
  366.             code=None,
  367.             failure_expression="py_retval != Py_None",
  368.             failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be None");')
  369.  
  370. argtypes.matcher.register_reverse_ret('void', VoidReturn)
  371. argtypes.matcher.register_reverse_ret('none', VoidReturn)
  372.  
  373. class GObjectParam(Parameter):
  374.  
  375.     def get_c_type(self):
  376.         return self.props.get('c_type', 'GObject *')
  377.  
  378.     def convert_c2py(self):
  379.         self.wrapper.add_declaration("PyObject *py_%s = NULL;" % self.name)
  380.         self.wrapper.write_code(code=("if (%s)\n"
  381.                                       "    py_%s = pygobject_new((GObject *) %s);\n"
  382.                                       "else {\n"
  383.                                       "    Py_INCREF(Py_None);\n"
  384.                                       "    py_%s = Py_None;\n"
  385.                                       "}"
  386.                                       % (self.name, self.name, self.name, self.name)),
  387.                                 cleanup=("Py_DECREF(py_%s);" % self.name))
  388.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  389.  
  390. argtypes.matcher.register_reverse('GObject*', GObjectParam)
  391.  
  392. class GObjectReturn(ReturnType):
  393.  
  394.     def get_c_type(self):
  395.         return self.props.get('c_type', 'GObject *')
  396.  
  397.     def write_decl(self):
  398.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  399.  
  400.     def write_error_return(self):
  401.         self.wrapper.write_code("return NULL;")
  402.  
  403.     def write_conversion(self):
  404.         self.wrapper.write_code("retval = (%s) pygobject_get(py_retval);"
  405.                                 % self.get_c_type())
  406.         self.wrapper.write_code("g_object_ref((GObject *) retval);")
  407.  
  408. argtypes.matcher.register_reverse_ret('GObject*', GObjectReturn)
  409.  
  410.  
  411.  
  412. class IntParam(Parameter):
  413.  
  414.     def get_c_type(self):
  415.         return self.props.get('c_type', 'int')
  416.  
  417.     def convert_c2py(self):
  418.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  419.         self.wrapper.write_code(code=("py_%s = PyInt_FromLong(%s);" %
  420.                                       (self.name, self.name)),
  421.                                 cleanup=("Py_DECREF(py_%s);" % self.name))
  422.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  423.  
  424. class IntReturn(ReturnType):
  425.     def get_c_type(self):
  426.         return self.props.get('c_type', 'int')
  427.     def write_decl(self):
  428.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  429.     def write_error_return(self):
  430.         self.wrapper.write_code("return -G_MAXINT;")
  431.     def write_conversion(self):
  432.         self.wrapper.write_code(
  433.             code=None,
  434.             failure_expression="!PyInt_Check(py_retval)",
  435.             failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be an int");')
  436.         self.wrapper.write_code("retval = PyInt_AsLong(py_retval);")
  437.  
  438. for argtype in ('int', 'gint', 'guint', 'short', 'gshort', 'gushort', 'long',
  439.                 'glong', 'gsize', 'gssize', 'guint8', 'gint8', 'guint16',
  440.                 'gint16', 'gint32', 'GTime'):
  441.     argtypes.matcher.register_reverse(argtype, IntParam)
  442.     argtypes.matcher.register_reverse_ret(argtype, IntReturn)
  443.  
  444.  
  445. class GEnumReturn(IntReturn):
  446.     def write_conversion(self):
  447.         self.wrapper.write_code(
  448.             code=None,
  449.             failure_expression=("pyg_enum_get_value(%s, py_retval, (gint *)&retval)" %
  450.                                 self.props['typecode']))
  451.  
  452. argtypes.matcher.register_reverse_ret("GEnum", GEnumReturn)
  453.  
  454. class GEnumParam(IntParam):
  455.     def convert_c2py(self):
  456.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  457.         self.wrapper.write_code(code=("py_%s = pyg_enum_from_gtype(%s, %s);" %
  458.                                       (self.name, self.props['typecode'], self.name)),
  459.                                 cleanup=("Py_DECREF(py_%s);" % self.name),
  460.                                 failure_expression=("!py_%s" % self.name))
  461.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  462.  
  463. argtypes.matcher.register_reverse("GEnum", GEnumParam)
  464.  
  465. class GFlagsReturn(IntReturn):
  466.     def write_conversion(self):
  467.         self.wrapper.write_code(
  468.             code=None,
  469.             failure_expression=("pyg_flags_get_value(%s, py_retval, (gint *)&retval)" %
  470.                                 self.props['typecode']))
  471.  
  472. argtypes.matcher.register_reverse_ret("GFlags", GFlagsReturn)
  473.  
  474. class GFlagsParam(IntParam):
  475.     def convert_c2py(self):
  476.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  477.         self.wrapper.write_code(code=("py_%s = pyg_flags_from_gtype(%s, %s);" %
  478.                                       (self.name, self.props['typecode'], self.name)),
  479.                                 cleanup=("Py_DECREF(py_%s);" % self.name),
  480.                                 failure_expression=("!py_%s" % self.name))
  481.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  482.  
  483. argtypes.matcher.register_reverse("GFlags", GFlagsParam)
  484.  
  485.  
  486. class GtkTreePathParam(IntParam):
  487.     def convert_c2py(self):
  488.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  489.         self.wrapper.write_code(code=("py_%s = pygtk_tree_path_to_pyobject(%s);" %
  490.                                       (self.name, self.name)),
  491.                                 cleanup=("Py_DECREF(py_%s);" % self.name),
  492.                                 failure_expression=("!py_%s" % self.name))
  493.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  494.  
  495. argtypes.matcher.register_reverse("GtkTreePath*", GtkTreePathParam)
  496.  
  497.  
  498. class BooleanReturn(ReturnType):
  499.     def get_c_type(self):
  500.         return "gboolean"
  501.     def write_decl(self):
  502.         self.wrapper.add_declaration("gboolean retval;")
  503.     def write_error_return(self):
  504.         self.wrapper.write_code("return FALSE;")
  505.     def write_conversion(self):
  506.         self.wrapper.write_code("retval = PyObject_IsTrue(py_retval)? TRUE : FALSE;")
  507. argtypes.matcher.register_reverse_ret("gboolean", BooleanReturn)
  508.  
  509. class BooleanParam(Parameter):
  510.     def get_c_type(self):
  511.         return "gboolean"
  512.     def convert_c2py(self):
  513.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  514.         self.wrapper.write_code("py_%s = %s? Py_True : Py_False;"
  515.                                 % (self.name, self.name))
  516.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  517.  
  518. argtypes.matcher.register_reverse("gboolean", BooleanParam)
  519.  
  520.  
  521. class DoubleParam(Parameter):
  522.     def get_c_type(self):
  523.         return self.props.get('c_type', 'gdouble')
  524.     def convert_c2py(self):
  525.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  526.         self.wrapper.write_code(code=("py_%s = PyFloat_FromDouble(%s);" %
  527.                                       (self.name, self.name)),
  528.                                 cleanup=("Py_DECREF(py_%s);" % self.name))
  529.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  530.  
  531. class DoubleReturn(ReturnType):
  532.     def get_c_type(self):
  533.         return self.props.get('c_type', 'gdouble')
  534.     def write_decl(self):
  535.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  536.     def write_error_return(self):
  537.         self.wrapper.write_code("return -G_MAXFLOAT;")
  538.     def write_conversion(self):
  539.         self.wrapper.write_code(
  540.             code=None,
  541.             failure_expression="!PyFloat_AsDouble(py_retval)",
  542.             failure_cleanup='PyErr_SetString(PyExc_TypeError, "retval should be a float");')
  543.         self.wrapper.write_code("retval = PyFloat_AsDouble(py_retval);")
  544.  
  545. for argtype in ('float', 'double', 'gfloat', 'gdouble'):
  546.     argtypes.matcher.register_reverse(argtype, DoubleParam)
  547.     argtypes.matcher.register_reverse_ret(argtype, DoubleReturn)
  548.  
  549.  
  550. class GBoxedParam(Parameter):
  551.     def get_c_type(self):
  552.         return self.props.get('c_type').replace('const-', 'const ')
  553.     def convert_c2py(self):
  554.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  555.         ctype = self.get_c_type()
  556.         if ctype.startswith('const '):
  557.             ctype_no_const = ctype[len('const '):]
  558.             self.wrapper.write_code(
  559.                 code=('py_%s = pyg_boxed_new(%s, (%s) %s, TRUE, TRUE);' %
  560.                       (self.name, self.props['typecode'],
  561.                        ctype_no_const, self.name)),
  562.                 cleanup=("Py_DECREF(py_%s);" % self.name))
  563.         else:
  564.             self.wrapper.write_code(
  565.                 code=('py_%s = pyg_boxed_new(%s, %s, FALSE, FALSE);' %
  566.                       (self.name, self.props['typecode'], self.name)),
  567.                 cleanup=("Py_DECREF(py_%s);" % self.name))
  568.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  569.  
  570. argtypes.matcher.register_reverse("GBoxed", GBoxedParam)
  571.  
  572. class GBoxedReturn(ReturnType):
  573.     def get_c_type(self):
  574.         return self.props.get('c_type')
  575.     def write_decl(self):
  576.         self.wrapper.add_declaration("%s retval;" % self.get_c_type())
  577.     def write_error_return(self):
  578.         self.wrapper.write_code("return retval;")
  579.     def write_conversion(self):
  580.         self.wrapper.write_code(
  581.             failure_expression=("!pyg_boxed_check(py_retval, %s)" %
  582.                                 (self.props['typecode'],)),
  583.             failure_cleanup=('PyErr_SetString(PyExc_TypeError, "retval should be a %s");'
  584.                              % (self.props['typename'],)))
  585.         self.wrapper.write_code('retval = pyg_boxed_get(py_retval, %s);' %
  586.                                 self.props['typename'])
  587.  
  588. argtypes.matcher.register_reverse_ret("GBoxed", GBoxedReturn)
  589.  
  590.  
  591. class GdkRectanglePtrParam(Parameter):
  592.     def get_c_type(self):
  593.         return self.props.get('c_type').replace('const-', 'const ')
  594.     def convert_c2py(self):
  595.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  596.         self.wrapper.write_code(
  597.             code=('py_%(name)s = Py_BuildValue("(ffff)", %(name)s->x, %(name)s->y,\n'
  598.                   '                            %(name)s->width, %(name)s->height);'
  599.                   % dict(name=self.name)),
  600.             cleanup=("Py_DECREF(py_%s);" % self.name))
  601.         self.wrapper.add_pyargv_item("py_%s" % self.name)
  602.  
  603. argtypes.matcher.register_reverse("GdkRectangle*", GdkRectanglePtrParam)
  604.  
  605.  
  606. class PyGObjectMethodParam(Parameter):
  607.     def __init__(self, wrapper, name, method_name, **props):
  608.         Parameter.__init__(self, wrapper, name, **props)
  609.         self.method_name = method_name
  610.  
  611.     def get_c_type(self):
  612.         return self.props.get('c_type', 'GObject *')
  613.  
  614.     def convert_c2py(self):
  615.         self.wrapper.add_declaration("PyObject *py_%s;" % self.name)
  616.         self.wrapper.write_code(code=("py_%s = pygobject_new((GObject *) %s);" %
  617.                                       (self.name, self.name)),
  618.                                 cleanup=("Py_DECREF(py_%s);" % self.name),
  619.                                 failure_expression=("!py_%s" % self.name))
  620.         self.wrapper.set_call_target("py_%s" % self.name, self.method_name)
  621.  
  622. class CallbackInUserDataParam(Parameter):
  623.     def __init__(self, wrapper, name, free_it, **props):
  624.         Parameter.__init__(self, wrapper, name, **props)
  625.         self.free_it = free_it
  626.  
  627.     def get_c_type(self):
  628.         return "gpointer"
  629.  
  630.     def convert_c2py(self):
  631.         self.wrapper.add_declaration("PyObject **_user_data;")
  632.         cleanup = self.free_it and ("g_free(%s);" % self.name) or None
  633.         self.wrapper.write_code(code=("_real_user_data = (PyObject **) %s;"
  634.                                       % self.name),
  635.                                 cleanup=cleanup)
  636.  
  637.         self.wrapper.add_declaration("PyObject *py_func;")
  638.         cleanup = self.free_it and "Py_DECREF(py_func);" or None
  639.         self.wrapper.write_code(code="py_func = _user_data[0];",
  640.                                 cleanup=cleanup)
  641.         self.wrapper.set_call_target("py_func")
  642.  
  643.         self.wrapper.add_declaration("PyObject *py_user_data;")
  644.         cleanup = self.free_it and "Py_XDECREF(py_user_data);" or None
  645.         self.wrapper.write_code(code="py_user_data = _user_data[1];",
  646.                                 cleanup=cleanup)
  647.         self.wrapper.add_pyargv_item("py_user_data", optional=True)
  648.  
  649. def _test():
  650.     import sys
  651.  
  652.     wrapper = ReverseWrapper("this_is_the_c_function_name", is_static=True)
  653.     wrapper.set_return_type(StringReturn(wrapper))
  654.     wrapper.add_parameter(PyGObjectMethodParam(wrapper, "self", method_name="do_xxx"))
  655.     wrapper.add_parameter(StringParam(wrapper, "param2", optional=True))
  656.     wrapper.add_parameter(GObjectParam(wrapper, "param3"))
  657.     wrapper.generate(FileCodeSink(sys.stderr))
  658.  
  659.     wrapper = ReverseWrapper("this_a_callback_wrapper")
  660.     wrapper.set_return_type(VoidReturn(wrapper))
  661.     wrapper.add_parameter(StringParam(wrapper, "param1", optional=False))
  662.     wrapper.add_parameter(GObjectParam(wrapper, "param2"))
  663.     wrapper.add_parameter(CallbackInUserDataParam(wrapper, "data", free_it=True))
  664.     wrapper.generate(FileCodeSink(sys.stderr))
  665.  
  666. if __name__ == '__main__':
  667.     _test()
  668.